import re
import logging
from django.contrib.auth import login, authenticate, logout
from django.http import JsonResponse
from django.views import View
from django_redis import get_redis_connection

from apps.carts.utils import merge_cookie_to_redis
from apps.goods.models import SKU
from apps.users.models import User, Address

import json

from celery_tasks.email.tasks import celery_send_email
from utils.Views import LoginRequiredJSONMixin

"""
需求分析： 根据页面的功能（从上到下，从左到右），哪些功能需要和后端配合完成
如何确定 哪些功能需要和后端进行交互呢？？？
        1.经验
        2.关注类似网址的相似功能

"""

"""
判断用户名是否重复的功能。

前端(了解)：     当用户输入用户名之后，失去焦点， 发送一个axios(ajax)请求

后端（思路）：
    请求:         接收用户名 
    业务逻辑：     
                    根据用户名查询数据库，如果查询结果数量等于0，说明没有注册
                    如果查询结果数量等于1，说明有注册
    响应          JSON 
                {code:0,count:0/1,errmsg:ok}

    路由      GET         usernames/<username>/count/        
   步骤：
        1.  接收用户名
        2.  根据用户名查询数据库
        3.  返回响应         

"""


class UsernameCountView(View):
    def get(self, request, username):
        """
        查询用户名是否注册
        :param request: 请求对象
        :param username: 用户名
        :return: JSON
        """
        # 1.  接收用户名，对这个用户名进行一下判断.此处使用路由转换器来进行优化
        # if not re.match('[a-zA-Z0-9_-]{5,20}', username):
        #     return JsonResponse({'code': 200, 'errmsg': '用户名不满足需求'})
        # 2.  根据用户名查询数据库
        count = User.objects.filter(username=username).count()
        # 3.  返回响应
        return JsonResponse({'code': 0, 'count': count, 'errmsg': 'ok'})


class MobileCountView(View):
    """判断手机号是否重复注册"""

    def get(self, request, mobile):
        """
        :param request: 请求对象
        :param mobile:  手机号
        :return:    JSON
        """
        count = User.objects.filter(mobile=mobile).count()
        return JsonResponse({'code': 0, 'errmsg': 'OK', 'count': count})


class RegisterView(View):
    """用户注册"""

    def post(self, request):
        """
        实现用户注册
        :param request: 请求对象
        :return: 注册结果
        """
        # 1. 接收请求（POST------JSON）

        # 从请求体中获取原始的JSON数据，bytes类型的
        json_bytes = request.body
        print(type(json_bytes))
        # 将bytes类型的JSON数据，转成JSON字符串
        json_str = json_bytes.decode()
        # 将JSON字符串，转成python的标准字典
        json_dict = json.loads(json_str)
        print(json_dict)

        # 2. 获取数据
        username = json_dict.get('username')
        password = json_dict.get('password')
        password2 = json_dict.get('password2')
        mobile = json_dict.get('mobile')
        allow = json_dict.get('allow')

        # 3. 验证数据
        #     3.1 用户名，密码，确认密码，手机号，是否同意协议 都要有
        #     all([xxx,xxx,xxx])
        #     all里的元素 只要是 None,False,0,空
        #     all 就返回False，否则返回True
        if not all([username, password, password2, mobile, allow]):
            return JsonResponse({'code': 400, 'errmsg': '参数不全'})

        # 用户名: 请输入5-20个字符的用户名且不能为纯数字
        if not re.match('[a-zA-z_-]{5,20}', username):
            return JsonResponse({'code': 400, 'errmsg': '用户名不满足规则'})

        # 判断密码是否是8-20个数字
        if not re.match('^[0-9A-Za-z]{8,20}$', password):
            return JsonResponse({'code': 400, 'errmsg': '密码格式有误!'})

        # 判断两次密码是否一致
        if password != password2:
            return JsonResponse({'code': 400, 'errmsg': '两次输入不对!'})

        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'errmsg': 'mobile格式有误!'})

        # 判断是否勾选用户协议
        if allow is not True:
            return JsonResponse({'code': 400, 'errmsg': 'allow格式有误!'})

        # 4. 数据入库
        # 4.1
        # user=User(username=username,password=password,mobile=mobile)
        # user.save()
        # 4.2
        # User.objects.create(username=username,password=password,mobile=mobile)

        # 以上2中方式，都是可以数据入库的
        # 但是 有一个问题 密码没有加密
        # 这里使用Django认证系统用户模型类提供的create_user()方法创建新的用户。
        # 这里create_user()方法中封装了set_password()方法加密密码。
        try:

            user = User.objects.create_user(username=username, password=password, mobile=mobile)
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '注册失败!%s' % e})

        # 如何设置session信息
        request.session['user_id'] = user.id

        # 系统（Django）为我们提供了 状态保持的方法
        login(request, user)

        # 5. 返回响应
        return JsonResponse({"code": 0, 'errmsg': '注册成功!'})


class LoginView(View):
    """
    用户登录
    """

    def post(self, request):
        # 1. 接收数据
        data = json.loads(request.body.decode())
        username = data.get('username')
        password = data.get('password')
        remembered = data.get('remembered')
        # 2. 验证数据
        if not all([username, password]):
            return JsonResponse({"code": 400, "errmsg": "参数不全"})

        # 确定 我们是根据手机号查询 还是 根据用户名查询
        # USERNAME_FIELD 我们可以根据 修改 User. USERNAME_FIELD 字段
        # 来影响authenticate 的查询
        # authenticate 就是根据 USERNAME_FIELD 来查询
        if re.match('1[3-9]\d{9}', username):
            User.USERNAME_FIELD = 'mobile'
        else:
            User.USERNAME_FIELD = 'username'

        # 3. 验证用户名和密码是否正确
        user = authenticate(username=username, password=password)
        # 判断是否为空,如果为空,返回
        if user is None:
            return JsonResponse({'code': 400, 'errmsg': '用户名或者密码错误'})

        # 4. session
        login(request, user)
        # 5. 判断是否记住登录
        if remembered:
            # 记住登录 -- 2周 或者 1个月 具体多长时间 产品说了算，None默认是两周
            request.session.set_expiry(None)
        else:
            request.session.set_expiry(0)
        # 6. 返回响应
        response = JsonResponse({'code': 0, 'errmsg': 'OK'})
        # 注册时用户名写入到cookie，有效期15天
        response.set_cookie("username", user.username, max_age=3600 * 24 * 15)
        response = merge_cookie_to_redis(request, response)
        return response


class LogoutView(View):
    """
    退出登录
    """

    def delete(self, request):
        logout(request)
        # 退出登录后，重定向到登录页面
        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        response.delete_cookie('username')
        return response


class CenterView(LoginRequiredJSONMixin, View):
    """ 用户中心，也必须是登录用户 """

    def get(self, request):
        """ 提供个人信息界面 """
        # request.user 就是 已经登录的用户信息
        # request.user 是来源于 中间件
        info_data = {
            'username': request.user.username,
            'email': request.user.email,
            'mobile': request.user.mobile,
            'email_active': request.user.email_active
        }
        return JsonResponse({"code": 0, "errmsg": "ok", 'info_data': info_data})


class EmailView(View):
    """添加邮箱"""

    def put(self, request):
        # 1、接受参数
        json_dict = json.loads(request.body.decode())
        email = json_dict.get('email')

        # 2、校验参数
        if not email:
            return JsonResponse({'code': 400, 'errmsg': '缺少email参数'})

        # if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
        #     return JsonResponse({'code': 400, 'errmsg': '参数email有误'})

        try:
            # 3、保存邮箱数据
            request.user.email = email
            request.user.save()
        except Exception as e:
            logging.error(e)

        # 4、发送一封激活邮件
        subject = '美多商城激活邮件'
        message = ""
        from_email = '美多商城<qi_rui_hua@163.com>'
        recipient_list = ['275242453@qq.com']
        token = request.user.id

        verify_url = "http://www.meiduo.site:8080/success_verify_email.html?token=%s" % token
        html_message = '<p>尊敬的用户您好！</p>' \
                       '<p>感谢您使用美多商城。</p>' \
                       '<p>您的邮箱为：%s 。请点击此链接激活您的邮箱：</p>' \
                       '<p><a href="%s">%s<a></p>' % (email, verify_url, verify_url)
        """
        subject, message, from_email, recipient_list
        subject：主题
        message：邮件内容
        from_email：发件人
        recipient_list：收件人列表
        """

        # 不使用异步消费
        # send_mail(subject=subject,
        #           message=message,
        #           from_email=from_email,
        #           recipient_list=recipient_list,
        #           html_message=html_message)
        # 使用异步消费
        celery_send_email.delay(
            subject=subject,
            message=message,
            from_email=from_email,
            recipient_list=recipient_list,
            html_message=html_message)
        return JsonResponse({'code': 0, 'errmsg': '添加邮箱成功'})


"""
需求（知道我们要干什么？？？）：
    激活用户的邮件
前端(用户干了什么，传递了什么参数)：
        用户会点击那个激活连接。那个激活连接携带了token
后端：
    请求：         接收请求，获取参数，验证参数
    业务逻辑：       user_id, 根据用户id查询数据，修改数据
    响应：         返回响应JSON

    路由：         PUT     emails/verification/  说明： token并没有在body里
    步骤：

        1. 接收请求
        2. 获取参数
        3. 验证参数
        4. 获取user_id
        5. 根据用户id查询数据
        6. 修改数据
        7. 返回响应JSON

"""


class EmailVerifyView(View):

    def put(self, request):
        params = request.GET
        token = params.get('token')
        if token is None:
            return JsonResponse({'code': 400, 'errmsg': '参数缺失'})

        user = User.objects.get(id=token)
        user.email_active = True
        user.save()
        return JsonResponse({'code': 0, 'errmsg': 'ok'})


class CreateAddressView(LoginRequiredJSONMixin, View):
    """新增地址"""

    def post(self, request):
        """实现新增地址逻辑"""
        # 判断是否超过地址上限：最多20个
        # Address.objects.filter(user=request.user).count()
        count = request.user.addresses.count()
        # if count >= constants.USER_ADDRESS_COUNTS_LIMIT:
        #     return JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})

        # 1、获取参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        user = request.user
        # 2、检验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 400, 'errmsg': '参数不全'})

        if not re.match('1[3-9]\d{9}', mobile):
            return JsonResponse({'code': 400, 'errmsg': '参数mobile有误'})

        # if not re.match('(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})', tel):
        #     return JsonResponse({'code': 400, 'errmsg': '参数tel有误'})

        # if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
        #     return JsonResponse({'code': 400, 'errmsg': '参数邮箱有误'})

        # 3、数据入库
        address = Address.objects.create(
            user=user,
            title=receiver,
            receiver=receiver,

            # province是省对象,
            province_id=province_id,
            city_id=city_id,
            district_id=district_id,
            place=place,
            mobile=mobile,
            tel=tel,
            email=email
        )

        address_dict = {
            'id': address.id,
            'title': address.title,
            'receiver': address.receiver,
            'province': address.province.name,
            'city': address.city.name,
            'district': address.district.name,
            'place': address.place,
            'mobile': address.mobile,
            'tel': address.tel,
            'email': address.email
        }

        return JsonResponse({'code': 0, 'errmsg': 'ok', 'address': address_dict})


# 地址展示
class AddressView(View):
    """查询用户收货地址"""

    def get(self, request):
        addresses = Address.objects.filter(user=request.user, is_deleted=False)

        # 创建空的列表
        address_dict_list = []
        for address in addresses:
            address_dict = {
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            }

            """因为没有默认地址，导致这样写会有BUG"""
            # 将默认地址移动到最前面
            # default_address = request.user.default_address
            # if default_address.id == address.id:
            #     # 查询集 addresses 没有 insert 方法
            #     address_dict_list.insert(0, address_dict)
            # else:
            #     address_dict_list.append(address_dict)
            address_dict_list.append(address_dict)
        default_id = request.user.default_address_id

        return JsonResponse({'code': 0,
                             'errmsg': 'ok',
                             'addresses': address_dict_list,
                             'default_address_id': default_id})


class UpdateDestroyAddressView(LoginRequiredJSONMixin, View):
    """修改和删除地址"""

    def put(self, request, address_id):
        # 1、获取参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 2、参数校验
        # 省略

        # 3、判断地址是否存在，并更新地址信息
        try:
            Address.objects.filter(id=address_id).update(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                tel=tel,
                email=email
            )
        except Exception as e:
            logging.error('更新地址失败%s' % e)
            return JsonResponse({'code': 400, 'errmsg': '更新地址失败'})
        # 4、构造响应数据
        address = Address.objects.get(id=address_id)
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        # 4、构造响应数据
        return JsonResponse({'code': 0, 'errmsg': '更新地址成功', 'address': address_dict})

    def delete(self, request, address_id):
        """删除地址"""

        # 1、查询要删除的地址
        address = Address.objects.get(id=address_id)

        # 将地址逻辑删除设置为True
        address.is_deleted = True
        address.save()
        return JsonResponse({'code': 0, 'errmsg': '删除地址成功'})


class DefaultAddressView(LoginRequiredJSONMixin, View):
    """设置默认地址"""
    def put(self, request, address_id):
        # 1、 接收参数,查询地址
        address = Address.objects.get(id=address_id)

        # 2、设置默认地址
        request.user.default_address = address
        request.user.save()

        return JsonResponse({'code': 0, 'errmsg': '设置默认地址成功'})


class UpdateTitleAddressView(LoginRequiredJSONMixin, View):
    """设置地址标题"""

    def put(self, request, address_id):
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')
        address = Address.objects.get(id=address_id)
        address.title = title
        address.save()
        return JsonResponse({'code': 0, 'errmsg': '设置地址标题成功'})


class ChangePasswordView(LoginRequiredJSONMixin, View):
    """修改密码"""
    def put(self, request):
        # 1、获取参数
        json_dict = json.loads(request.body.decode())

        old_password = json_dict.get('old_password')
        new_password = json_dict.get('new_password')
        new_password2 = json_dict.get('new_password2')

        result = request.user.check_password(old_password)
        if not result:
            return JsonResponse({'code': 400, 'errmsg': '原始密码不正确'})

        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return JsonResponse({'code': 400, 'errmsg': '密码最少8位,最长20位'})

        if new_password != new_password2:
            return JsonResponse({'code': 400, 'errmsg': '两次输入密码不一致'})

        request.user.set_password(new_password)
        request.user.save()

        # return JsonResponse({'code': 0, 'errmsg': ' ok'})

        # 清理状态保持信息,退出
        logout(request)
        response = JsonResponse({'code': 0, 'errmsg': ' ok'})
        response.delete_cookie('username')
        return response


class UserHistoryView(View):

    def post(self, request):

        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')

        # 校验参数
        try:
            SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': 'sku不存在'})

        # 保存用户浏览数据
        redis_conn = get_redis_connection('history')
        pl = redis_conn.pipeline()
        user_id = request.user.id

        # 先去重
        pl.lrem('history_%s' % user_id, 0, sku_id)
        # 再存储
        pl.lpush('history_%s' % user_id, sku_id)
        # 最后截取
        pl.ltrim('history_%s' % user_id, 0, 4)
        # 执行管道
        pl.execute()

        # 响应结果
        return JsonResponse({'code': 0, 'errmsg': 'OK'})

    def get(self, request):
        # 1. 连接redis
        redis_cli = get_redis_connection('history')
        # 2. 获取redis数据
        ids = redis_cli.lrange('history_%s' % request.user.id, 0, 4)
        history_list = []
        for sku_id in ids:
            sku = SKU.objects.get(id=sku_id)
            history_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })
        # 5. 返回JSON
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'skus': history_list})
